1 - Funções
·
Funções são uma das características mais importantes
da linguagem C; o local onde toda a atividade do programa ocorre.
·
As funções
dividem grandes tarefas de computação em tarefas menores.
·
Permitem às pessoas trabalharem sobre o que outras já
fizeram.
·
Podem esconder detalhes de operação que não necessitam
ser conhecidos.
·
Facilitam mudanças, já que cada função resolve um
problema menor.
·
C utiliza várias pequenas funções eficientes e fáceis
de usar (biblioteca).
·
O programa pode residir em vários arquivos-fonte.
·
Os arquivos-fonte podem ser compilados separadamente e
carregados juntos, com funções de bibliotecas previamente compiladas.
·
Com o padrão ANSI, é possível declarar os tipos dos
argumentos quando uma função é declarada.
·
A nova sintaxe possibilita às declarações casarem com
as definições das funções, tornando possível uma melhor detecção de erros.
·
Observe o programa
abaixo para cálculo do fatorial de um número inteiro.
#include <stdio.h>
#include <conio.h>
void main() {
int numero, fatorial, fator;
clrscr();
printf("\nValor para o fatorial:");
scanf("%d", &numero);
fatorial = 1;
for(fator = 1; fator <= numero; fator++) {
fatorial = fatorial *
fator;
}
printf("\nFatorial de %d = %d", numero, fatorial);
}
·
Podemos representar o processamento para cálculo do
fatorial através de uma função. Nesse caso, o programa acima seria:
#include <stdio.h>
#include <conio.h>
void main() {
int numero;
int fatorial(int valor);
clrscr();
printf("\nValor para o fatorial:");
scanf("%d", &num);
printf("\nFatorial de %d = %d", num, fatorial(num));
}
int fatorial(int numero) {
int fator, fat;
fat = 1;
for(fator = 1; fator <= numero; fator++) {
fat = fat * fator;
}
return fat;
}
·
Outro exemplo de uso de função:
#include <stdio.h>
#include
<conio.h>
/* Programa para gera
uma tabela de conversão de
graus Celcius para Farenheit, com valores
de
Farenheit = -10.0, -9.5, -9.0, ... , 9.5, 10.0
*/
void main() {
int numero;
float gfparagc(float tempf);
clrscr();
printf("\Graus Farenheit
Graus Celcius\n");
for(grausf = -10.0; grausf <= 10.0;
grausf += 0.5) {
grausc = 5.0 / 9 * (grausf – 32);
printf("
%12.3f %12.3\n", grausf,
gfparagc(grausf));
}
}
float gfparagc(float
farenheit) {
return 5.0 / 9 * (farenheit – 32);
}
·
Forma geral de definição de uma função:
tipo-retorno nome(declarações de parâmetros) {
declarações e comandos - corpo da função
}
·
A lista de declaração de parâmetros para uma função
tem esta forma geral:
func(tipo nomeVar1, tipo nomeVar2, …, tipo nomeVar3) {
·
A menor função que poderíamos escrever:
vazia() {}
·
Quando o tipo de retorno não é especificado
considera-se o tipo int.
·
A comunicação entre funções é feita essencialmente
através de: argumentos e retorno.
·
Os argumentos de
uma função são passados na sua chamada.
. . .
func(valor1, valor2);
. . .
·
O retorno do valor de uma função é realizado pelo
comando return.
return expressão;
·
O comando return
tem duas funcionalidades: provocar uma saída imediata da função que o contém,
devolver um valor ao programa chamador.
·
A chamada da função pode ignorar o valor retornado.
·
As funções podem
retornar valores numéricos ou literais, além de apontadores.
·
Se o tipo do retorno da função é void, pode-se
deixar de colocar o comando return.
·
O controle retorna sempre que o fluxo atinge o último
comando da função mesmo sem return.
·
Regras de escopo
de uma linguagem são as regras que determinam se um trecho de código conhece ou
tem acesso a outro trecho de código ou dados.
·
Em C, cada função
é um bloco de código.
·
O código e os
dados que são definidos internamente em uma função não podem interagir com o
código ou dados definidos em uma outra função porque as duas têm escopos
diferentes.
·
Variáveis
internas a uma função são chamadas variáveis locais.
·
Variáveis locais
não são reconhecidas (acessíveis) fora de seu próprio bloco de código.
·
O ciclo de vida
de uma variável local está associado à execução da função – variáveis existem
enquanto o bloco de código em que foram declaradas está sendo executado.
·
Ao contrário das
variáveis locais, variáveis globais, aquelas que são definidas fora das
funções, são reconhecidas pelo programa inteiro e podem ser usadas por qualquer
trecho de código.
. . .
void func1(void);
void func2(void);
int contador; /*
contador é uma variável global */
void main() {
. . .
contador = 100;
func1();
. . .
}
void func1(void) {
int temp;
temp = contador;
. . .
func2();
printf(“O valor de contador eh %d”, contador);
}
void func2(void) {
int indice, contador; /* contador é uma variável local */
contador = 0;
for(indice = 0; indice < 10; i++) {
if(…) {
contador++;
}
}
printf(“O valor de contador eh %d”, contador);
}
·
Em C, todas as
funções estão no mesmo nível de escopo, isto é, não é possível definir
uma função internamente a uma outra função.
·
Os
especificadores de tipo de classe de armazenamento são aplicados às variáveis
locais e/ou globais. Tais especificadores servem para indicar ao compilador
como uma variável deve ser armazenada:
§ extern – avisa ao compilador que a variável foi definida em outro arquivo e que sua compilação será em separado.
§ static – avisa ao compilador que o conteúdo da variável local será conservado para as próximas chamadas da função.
§ register – avisa ao compilador que esta variável não será alocada na memória principal e sim num registrador da CPU.
·
Exemplo:
void serie (void) {
static int num_serie = 0;
/*variaveis locais estaticas*/
num_serie = num_serie++;
return (num_serie);
}
·
Se uma função usa
argumentos, ela deve declarar variáveis que receberão os valores dos
argumentos; tais variáveis são denominadas parâmetros formais.
·
Os parâmetros
formais se comportam como qualquer outra variável local dentro da função.
·
Aproveitando a definição
da função fatorial(), já mostrada:
int fatorial(int numero){
. . .
}
·
A função fatorial()
tem um único parâmetro: numero. É preciso assegurar-se de que os
argumentos usados para chamar a função sejam compatíveis com o tipo de seus parâmetros.
·
Incompatibilidade
de tipos não são detectadas pelo compilador mas podem gerar resultados
inesperados – o uso de protótipos de funções pode ajudar a achar esses tipos de
erros, como veremos mais adiante.
·
Por exemplo:
experimente chamar a função fatorial() da seguinte maneira:
#include <stdio.h>
#include <conio.h>
void main() {
int numero;
clrscr();
printf("\nValor para o fatorial:");
scanf("%d", &numero);
printf("\nFatorial de %d = %d", numero,
fatorial(“erro”));
}
·
Ocorreram erros
de compilação? Qual o valor retornado?
·
Agora inclua no
programa acima o protótipo da função fatorial:
#include <stdio.h>
int fatorial(int);
. . .
·
Quais as mudanças
em relação ao comportamento do compilador?
·
Os argumentos
para funções são passados de duas maneiras: chamadas por valor ou por
referência.
·
Na chamada por
valor, copia-se o valor de um argumento no parâmetro formal da função. Nesse
caso, alterações feitas no parâmetro da função não têm nenhum efeito sobre as
variáveis usadas para chamá-la.
·
Na chamada por
referência, o endereço é usado para acessar o argumento real passado na chamada
da função. Nesse caso, as alterações feitas no parâmetro afetam a variável
usada para chamar a função.
·
No uso da função fatorial(),
verifica-se a chamada por valor.
int fatorial(int);
. . .
printf("\nFatorial de %d =
%d", num, fatorial(num));
. . .
·
Observe este
outro exemplo de passagem de parâmetros por valor:
/*
Cálculo do Máximo Divisor Comum entre dois
inteiros
*/
#include <stdio.h>
#include <conio.h>
int leInteiro();
int mdc(int, int);
void main() {
clrscr();
printf¨("Cáculo do MDC entre dois
números:\n\n";
printf¨("MDC = %d\n", mdc(leInteiro(), leInteiro()));
}
int leInteiro() {
int inteiro;
printf("Informe o valor de um inteiro: \n");
scanf("%d", &inteiro);
return inteiro;
}
int mdc(int primeiro,
int segundo) {
while(primeiro != segundo) {
if(primeiro > segundo) {
primeiro = primeiro – segundo;
else {
segundo = segundo – primeiro;
}
}
}
·
Veremos a
passagem de parâmetros por referência no próximo capítulo, quando aprenderemos
a lidar com apontadores.
·
É possível passar
informações para a função main() através de argumentos da linha de
comandos.
·
Um argumento da
linha de comandos é a informação que segue o nome do programa na linha de
comandos do sistema operacional. Por exemplo: (no DOS)
C:\>cd turbo_C
·
Há dois
argumentos internos especiais: argc e argv, que são usados para
receber os argumentos da linha de comandos.
·
O argc
contém o número de argumentos da linha de comandos e é um inteiro (seu valor é,
no mínimo, 1, porque o nome do programa é qualificado como primeiro argumento).
·
O argv é
um apontador para um vetor de apontadores para caracteres. Cada elemento nesse
vetor aponta para um argumento da linha de comandos (no caso, strings).
·
Um exemplo
simples:
. . .
/* programa para
mostrar mensagem de boas-vindas */
void main(int argc, char *argv[]) {
clrscr();
if(argc
!= 2) {
printf(“\nERRO: voce esqueceu de digitar seu nome!”);
exit(1); /* execucao do programa eh finalizada */
}
printf(“Bem-vindo %s!!!”, argv[1]);
}